package com.example.controller;

import com.example.model.LaundryOrder;
import com.example.model.User;
import com.example.service.LaundryOrderService;
import com.example.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/laundry")
@Tag(name = "Laundry Order Management", description = "Laundry order creation, query, update and management")
@Transactional(readOnly = true)
public class LaundryController {

    @Autowired
    private LaundryOrderService laundryOrderService;

    @Autowired
    private UserService userService;

    @PostMapping("/orders")
    @Operation(summary = "Create laundry order")
    @Transactional
    public ResponseEntity<Map<String, Object>> createOrder(@Valid @RequestBody Map<String, Object> orderData) {
        try {
            // Create order entity
            LaundryOrder order = new LaundryOrder();
            order.setOrderNumber("WO" + System.currentTimeMillis());
            order.setCustomerName((String) orderData.get("customerName"));
            order.setCustomerPhone((String) orderData.get("customerPhone"));
            order.setPickupAddress((String) orderData.get("pickupAddress"));
            order.setDeliveryAddress((String) orderData.get("deliveryAddress"));
            order.setNotes((String) orderData.get("notes"));
            
            // Set service type
            String serviceType = (String) orderData.get("serviceType");
            if (serviceType != null) {
                try {
                    order.setServiceType(LaundryOrder.ServiceType.valueOf(serviceType));
                } catch (IllegalArgumentException e) {
                    order.setServiceType(LaundryOrder.ServiceType.DRY_CLEANING);
                }
            }
            
            // Set amount
            Object totalAmountObj = orderData.get("totalAmount");
            if (totalAmountObj != null) {
                order.setTotalAmount(new BigDecimal(totalAmountObj.toString()));
                order.setFinalAmount(order.getTotalAmount());
            }
            
            // Set customer association
            Object customerObj = orderData.get("customer");
            if (customerObj instanceof Map) {
                Map<String, Object> customerMap = (Map<String, Object>) customerObj;
                Object customerIdObj = customerMap.get("id");
                if (customerIdObj != null) {
                    Long customerId = Long.valueOf(customerIdObj.toString());
                    userService.getUserById(customerId).ifPresent(order::setCustomer);
                }
            }
            
            LaundryOrder createdOrder = laundryOrderService.createOrder(order);
            Map<String, Object> dto = convertOrderToMap(createdOrder);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "Order created successfully");
            response.put("data", dto);
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("message", "Order creation failed: " + e.getMessage());
            return ResponseEntity.badRequest().body(errorResponse);
        }
    }

    @GetMapping("/orders")
    @Operation(summary = "Get laundry order list")
    public ResponseEntity<Map<String, Object>> getAllOrders(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "createdAt") String sortBy,
            @RequestParam(defaultValue = "desc") String sortDir,
            @RequestParam(required = false) String status,
            @RequestParam(required = false) Boolean statistics,
            @RequestParam(required = false) String period,
            @RequestParam(required = false) Boolean summary,
            @RequestParam(required = false) Boolean dashboard) {

        try {
            // If requesting statistics
            if (Boolean.TRUE.equals(statistics) || Boolean.TRUE.equals(dashboard)) {
                Page<LaundryOrder> allOrdersPage = laundryOrderService.findAll(PageRequest.of(0, 1000));
                List<LaundryOrder> allOrders = allOrdersPage.getContent();
                
                Map<String, Object> stats = new HashMap<>();
                stats.put("total", allOrders.size());
                stats.put("pending", allOrders.stream().filter(o -> o.getStatus() == LaundryOrder.OrderStatus.PENDING).count());
                stats.put("processing", allOrders.stream().filter(o -> o.getStatus() == LaundryOrder.OrderStatus.PROCESSING).count());
                stats.put("completed", allOrders.stream().filter(o -> o.getStatus() == LaundryOrder.OrderStatus.COMPLETED).count());
                stats.put("cancelled", allOrders.stream().filter(o -> o.getStatus() == LaundryOrder.OrderStatus.CANCELLED).count());
                
                return ResponseEntity.ok(stats);
            }

            Sort sort = Sort.by(Sort.Direction.fromString(sortDir), sortBy);
            Pageable pageable = PageRequest.of(page, size, sort);

            Page<LaundryOrder> orderPage;
            if (status != null && !status.isEmpty()) {
                try {
                    LaundryOrder.OrderStatus orderStatus = LaundryOrder.OrderStatus.valueOf(status.toUpperCase());
                    orderPage = laundryOrderService.findByStatus(orderStatus, pageable);
                } catch (IllegalArgumentException e) {
                    orderPage = laundryOrderService.findAll(pageable);
                }
            } else {
                orderPage = laundryOrderService.findAll(pageable);
            }

            // Convert to Map list safely
            List<Map<String, Object>> orderMaps = orderPage.getContent().stream()
                    .map(this::convertOrderToMap)
                    .collect(Collectors.toList());

            Map<String, Object> response = new HashMap<>();
            response.put("content", orderMaps);
            response.put("totalElements", orderPage.getTotalElements());
            response.put("totalPages", orderPage.getTotalPages());
            response.put("size", orderPage.getSize());
            response.put("number", orderPage.getNumber());

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("message", "Failed to get order list: " + e.getMessage());
            errorResponse.put("content", List.of());
            errorResponse.put("totalElements", 0);
            errorResponse.put("totalPages", 0);
            errorResponse.put("size", size);
            errorResponse.put("number", page);
            
            return ResponseEntity.ok(errorResponse);
        }
    }

    @GetMapping("/orders/{id}")
    @Operation(summary = "Get order details")
    public ResponseEntity<Map<String, Object>> getOrderDetail(@PathVariable Long id) {
        try {
            return laundryOrderService.findById(id)
                    .map(order -> {
                        Map<String, Object> dto = convertOrderToMap(order);
                        Map<String, Object> response = new HashMap<>();
                        response.put("success", true);
                        response.put("data", dto);
                        return ResponseEntity.ok(response);
                    })
                    .orElse(ResponseEntity.notFound().build());
        } catch (Exception e) {
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("message", "Failed to get order details: " + e.getMessage());
            return ResponseEntity.badRequest().body(errorResponse);
        }
    }

    @PutMapping("/orders/{id}/status")
    @Operation(summary = "Update order status")
    @Transactional
    public ResponseEntity<Map<String, Object>> updateOrderStatus(
            @PathVariable Long id,
            @RequestBody Map<String, Object> statusUpdate) {

        try {
            String status = (String) statusUpdate.get("status");
            String notes = (String) statusUpdate.get("notes");

            LaundryOrder.OrderStatus orderStatus = LaundryOrder.OrderStatus.valueOf(status.toUpperCase());
            LaundryOrder updatedOrder = laundryOrderService.updateOrderStatus(id, orderStatus);

            if (notes != null && !notes.isEmpty()) {
                updatedOrder.setNotes(notes);
                updatedOrder = laundryOrderService.updateOrder(updatedOrder);
            }

            Map<String, Object> dto = convertOrderToMap(updatedOrder);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "Order status updated successfully");
            response.put("data", dto);
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("message", "Failed to update order status: " + e.getMessage());
            return ResponseEntity.badRequest().body(errorResponse);
        }
    }

    @DeleteMapping("/orders/{id}")
    @Operation(summary = "Delete laundry order")
    @Transactional
    public ResponseEntity<Map<String, Object>> deleteOrder(@PathVariable Long id) {
        try {
            if (laundryOrderService.findById(id).isPresent()) {
                laundryOrderService.deleteOrder(id);
                
                Map<String, Object> response = new HashMap<>();
                response.put("success", true);
                response.put("message", "Order deleted successfully");
                
                return ResponseEntity.ok(response);
            }
            return ResponseEntity.notFound().build();
        } catch (Exception e) {
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("success", false);
            errorResponse.put("message", "Failed to delete order: " + e.getMessage());
            return ResponseEntity.badRequest().body(errorResponse);
        }
    }

    /**
     * Safely convert LaundryOrder to Map to avoid lazy loading serialization issues
     */
    private Map<String, Object> convertOrderToMap(LaundryOrder order) {
        Map<String, Object> map = new HashMap<>();
        
        // Basic info
        map.put("id", order.getId());
        map.put("orderNumber", order.getOrderNumber());
        map.put("orderNo", order.getOrderNumber()); // Frontend compatibility
        
        // Customer info - safe handling of lazy loading
        try {
            if (order.getCustomer() != null) {
                map.put("customerId", order.getCustomer().getId());
                map.put("customerName", order.getCustomer().getUsername());
            }
        } catch (Exception e) {
            // Use order stored customer info when lazy loading fails
            map.put("customerId", null);
        }
        
        // Prefer order stored customer info
        if (order.getCustomerName() != null) {
            map.put("customerName", order.getCustomerName());
        }
        map.put("customerPhone", order.getCustomerPhone());
        
        // Enum type conversion
        map.put("status", order.getStatus() != null ? order.getStatus().name() : null);
        map.put("serviceType", order.getServiceType() != null ? order.getServiceType().name() : null);
        map.put("paymentStatus", order.getPaymentStatus() != null ? order.getPaymentStatus().name() : null);
        map.put("paymentMethod", order.getPaymentMethod() != null ? order.getPaymentMethod().name() : null);
        
        // Address info
        map.put("pickupAddress", order.getPickupAddress());
        map.put("deliveryAddress", order.getDeliveryAddress());
        
        // Time info
        map.put("pickupTime", order.getPickupTime());
        map.put("deliveryTime", order.getDeliveryTime());
        map.put("appointmentTime", order.getAppointmentTime());
        map.put("createdAt", order.getCreatedAt());
        map.put("createTime", order.getCreatedAt()); // Frontend compatibility
        map.put("updatedAt", order.getUpdatedAt());
        map.put("paidAt", order.getPaidAt());
        
        // Amount info
        map.put("totalAmount", order.getTotalAmount());
        map.put("amount", order.getTotalAmount()); // Frontend compatibility
        map.put("discountAmount", order.getDiscountAmount());
        map.put("finalAmount", order.getFinalAmount());
        
        // Other info
        map.put("notes", order.getNotes());
        map.put("specialRequirements", order.getSpecialRequirements());
        
        // Review info
        map.put("rating", order.getRating());
        map.put("review", order.getReview());
        map.put("reviewedAt", order.getReviewedAt());
        
        // Order items - safe handling of lazy loading
        map.put("items", List.of()); // Temporarily set to empty list
        
        return map;
    }
}
